home *** CD-ROM | disk | FTP | other *** search
/ Software of the Month Club 2000 October / Software of the Month - Ultimate Collection Shareware 277.iso / pc / PROGRAMS / UTILITY / WINLINUX / DATA1.CAB / programs_-_include / ASM-ALPH.{_4 / SEMAPHOR.{1H < prev    next >
Text File  |  1999-09-17  |  5KB  |  197 lines

  1. #ifndef _ALPHA_SEMAPHORE_H
  2. #define _ALPHA_SEMAPHORE_H
  3.  
  4. /*
  5.  * SMP- and interrupt-safe semaphores..
  6.  *
  7.  * (C) Copyright 1996 Linus Torvalds
  8.  * (C) Copyright 1996 Richard Henderson
  9.  */
  10.  
  11. #include <asm/current.h>
  12. #include <asm/system.h>
  13. #include <asm/atomic.h>
  14.  
  15. struct semaphore {
  16.     /* Careful, inline assembly knows about the position of these two.  */
  17.     atomic_t count;
  18.     atomic_t waking;        /* biased by -1 */
  19.     struct wait_queue *wait;
  20. };
  21.  
  22. #define MUTEX ((struct semaphore) \
  23.  { ATOMIC_INIT(1), ATOMIC_INIT(-1), NULL })
  24. #define MUTEX_LOCKED ((struct semaphore) \
  25.  { ATOMIC_INIT(0), ATOMIC_INIT(-1), NULL })
  26.  
  27. #define sema_init(sem, val)    atomic_set(&((sem)->count), val)
  28.  
  29. extern void __down(struct semaphore * sem);
  30. extern int  __down_interruptible(struct semaphore * sem);
  31. extern int  __down_trylock(struct semaphore * sem);
  32. extern void __up(struct semaphore * sem);
  33.  
  34. /* All have custom assembly linkages.  */
  35. extern void __down_failed(struct semaphore * sem);
  36. extern void __down_failed_interruptible(struct semaphore * sem);
  37. extern void __down_failed_trylock(struct semaphore * sem);
  38. extern void __up_wakeup(struct semaphore * sem);
  39.  
  40. /*
  41.  * Whee.  Hidden out of line code is fun.  The contention cases are
  42.  * handled out of line in kernel/sched.c; arch/alpha/lib/semaphore.S
  43.  * takes care of making sure we can call it without clobbering regs.
  44.  */
  45.  
  46. extern inline void down(struct semaphore * sem)
  47. {
  48.     /* Given that we have to use particular hard registers to 
  49.        communicate with __down_failed anyway, reuse them in 
  50.        the atomic operation as well. 
  51.  
  52.        __down_failed takes the semaphore address in $24, and
  53.        it's return address in $28.  The pv is loaded as usual.
  54.        The gp is clobbered (in the module case) as usual.  */
  55.  
  56.     __asm__ __volatile__ (
  57.         "/* semaphore down operation */\n"
  58.         "1:    ldl_l    $27,%0\n"
  59.         "    subl    $27,1,$27\n"
  60.         "    mov    $27,$28\n"
  61.         "    stl_c    $28,%0\n"
  62.         "    beq    $28,2f\n"
  63.         "    blt    $27,3f\n"
  64.         "4:    mb\n"
  65.         ".section .text2,\"ax\"\n"
  66.         "2:    br    1b\n"
  67.         "3:    lda    $24,%0\n"
  68.         "    jsr    $28,__down_failed\n"
  69.         "    ldgp    $29,0($28)\n"
  70.         "    br    4b\n"
  71.         ".previous"
  72.         : : "m"(sem->count)
  73.         : "$24", "$27", "$28", "memory");
  74. }
  75.  
  76. extern inline int down_interruptible(struct semaphore * sem)
  77. {
  78.     /* __down_failed_interruptible takes the semaphore address in $24,
  79.        and it's return address in $28.  The pv is loaded as usual.
  80.        The gp is clobbered (in the module case) as usual.  The return
  81.        value is in $24.  */
  82.  
  83.     register int ret __asm__("$24");
  84.  
  85.     __asm__ __volatile__ (
  86.         "/* semaphore down interruptible operation */\n"
  87.         "1:    ldl_l    $27,%1\n"
  88.         "    subl    $27,1,$27\n"
  89.         "    mov    $27,$28\n"
  90.         "    stl_c    $28,%1\n"
  91.         "    beq    $28,2f\n"
  92.         "    blt    $27,3f\n"
  93.         "    mov    $31,%0\n"
  94.         "4:    mb\n"
  95.         ".section .text2,\"ax\"\n"
  96.         "2:    br    1b\n"
  97.         "3:    lda    $24,%1\n"
  98.         "    jsr    $28,__down_failed_interruptible\n"
  99.         "    ldgp    $29,0($28)\n"
  100.         "    br    4b\n"
  101.         ".previous"
  102.         : "=r"(ret)
  103.         : "m"(sem->count)
  104.         : "$27", "$28", "memory");
  105.  
  106.     return ret;
  107. }
  108.  
  109. /*
  110.  * down_trylock returns 0 on success, 1 if we failed to get the lock.
  111.  *
  112.  * We must manipulate count and waking simultaneously and atomically.
  113.  * Do this by using ll/sc on the pair of 32-bit words.
  114.  */
  115.  
  116. extern inline int down_trylock(struct semaphore * sem)
  117. {
  118.     long ret, tmp, tmp2, sub;
  119.  
  120.     /* "Equivalent" C.  Note that we have to do this all without
  121.        (taken) branches in order to be a valid ll/sc sequence.
  122.  
  123.        do {
  124.            tmp = ldq_l;
  125.            sub = 0x0000000100000000;
  126.            ret = ((int)tmp <= 0);        // count =< 0 ?
  127.            if ((int)tmp >= 0) sub = 0;    // count >= 0 ?
  128.             // note that if count=0 subq overflows to the high
  129.             // longword (i.e waking)
  130.            ret &= ((long)tmp < 0);        // waking < 0 ?
  131.            sub += 1;
  132.            if (ret) 
  133.             break;    
  134.            tmp -= sub;
  135.            tmp = stq_c = tmp;
  136.        } while (tmp == 0);
  137.     */
  138.  
  139.     __asm__ __volatile__(
  140.         "1:    ldq_l    %1,%4\n"
  141.         "    lda    %3,1\n"
  142.         "    addl    %1,0,%2\n"
  143.         "    sll    %3,32,%3\n"
  144.         "    cmple    %2,0,%0\n"
  145.         "    cmovge    %2,0,%3\n"
  146.         "    cmplt    %1,0,%2\n"
  147.         "    addq    %3,1,%3\n"
  148.         "    and    %0,%2,%0\n"
  149.         "    bne    %0,2f\n"
  150.         "    subq    %1,%3,%1\n"
  151.         "    stq_c    %1,%4\n"
  152.         "    beq    %1,3f\n"
  153.         "2:\n"
  154.         ".section .text2,\"ax\"\n"
  155.         "3:    br    1b\n"
  156.         ".previous"
  157.         : "=&r"(ret), "=&r"(tmp), "=&r"(tmp2), "=&r"(sub)
  158.         : "m"(*sem)
  159.         : "memory");
  160.  
  161.     return ret;
  162. }
  163.  
  164. extern inline void up(struct semaphore * sem)
  165. {
  166.     /* Given that we have to use particular hard registers to 
  167.        communicate with __up_wakeup anyway, reuse them in 
  168.        the atomic operation as well. 
  169.  
  170.        __up_wakeup takes the semaphore address in $24, and
  171.        it's return address in $28.  The pv is loaded as usual.
  172.        The gp is clobbered (in the module case) as usual.  */
  173.  
  174.     __asm__ __volatile__ (
  175.         "/* semaphore up operation */\n"
  176.         "    mb\n"
  177.         "1:    ldl_l    $27,%0\n"
  178.         "    addl    $27,1,$27\n"
  179.         "    mov    $27,$28\n"
  180.         "    stl_c    $28,%0\n"
  181.         "    beq    $28,2f\n"
  182.         "    mb\n"
  183.         "    ble    $27,3f\n"
  184.         "4:\n"
  185.         ".section .text2,\"ax\"\n"
  186.         "2:    br    1b\n"
  187.         "3:    lda    $24,%0\n"
  188.         "    jsr    $28,__up_wakeup\n"
  189.         "    ldgp    $29,0($28)\n"
  190.         "    br    4b\n"
  191.         ".previous"
  192.         : : "m"(sem->count)
  193.         : "$24", "$27", "$28", "memory");
  194. }
  195.  
  196. #endif
  197.